package com.googlecode.fluentregex;

import java.util.Arrays;
import java.util.List;

public class RegularExpressionBuilder extends RegularExpressionBuilderBase {
	static final List<String> SPECIAL_CHARS = Arrays.asList("[", "\\", "^", "$", ".", "|", "?", "*", "+", "(", ")");
	
	
	public static RegularExpressionBuilder regExp() {
		return new RegularExpressionBuilder();
	}
	
	public RegularExpressionBuilder literal(String str) throws InvalidTokenException {
		if (str != null) {
			for (String special : SPECIAL_CHARS) {
				if (str.contains(special)) {
					throw new InvalidTokenException("'" + str + "' contains the special character: " + special);
				}
			}
			tokens.add(str);
		}
		return this;
	}

	public RegularExpressionBuilder string(String str) {
		if (str != null) {
			for (String special : SPECIAL_CHARS) {
				if (str.contains(special)) {
					str = str.replace(new StringBuffer(special), new StringBuffer("\\" + special));
				}
			}
			tokens.add(str);
		}
		return this;
	}
	
	public RegularExpressionBuilder anyTimes() {
		tokens.add("*");
		return this;
	}

	public RegularExpressionBuilder atLeastOne() {
		tokens.add("+");
		return this;
	}
	
	public RegularExpressionBuilder or() {
		tokens.add("|");
		return this;
	}

	public RegularExpressionBuilder times(int i, int j) {
		tokens.add("{" + i + "," + j + "}");
		return this;
	}
	
	public RegularExpressionBuilder times(int i) {
		tokens.add("{" + i + "}");
		return this;
	}

	public static RegularExpressionBuilder or(RegularExpressionBuilder reg1, RegularExpressionBuilder reg2) {
		if (reg1 != null && reg2 != null) {
			reg1.tokens.add("|");
			reg1.tokens.addAll(reg2.tokens);
			return reg1;
		}
		return null;
	}	

	public RegularExpressionBuilder group() {
		tokens.add(0, "(");
		tokens.add(")");
		return this;
	}
	
	public static RegularExpressionBuilder group(RegularExpressionBuilder reg) {
		reg.tokens.add(0, "(");
		reg.tokens.add(")");
		return reg;
	}

	public RegularExpressionBuilder letter() {
		tokens.add("[a-zA-Z]");
		return this;
	}

	public RegularExpressionBuilder numeral() {
		tokens.add("\\d");
		return this;
	}
	
	public RegularExpressionBuilder email() {
		tokens.add("[a-zA-Z0-9._%-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,4}");
		return this;
	}
	
	public RegularExpressionBuilder anyOf(SingleCharMatcher singleCharMatcher) {
		return anyOf(false, singleCharMatcher);
	}
	
	public RegularExpressionBuilder anyOf(boolean exclude, SingleCharMatcher singleCharMatcher) {
		StringBuffer anyOf = new StringBuffer("[");
		if (exclude) {
			anyOf.append("^");
		}
		anyOf.append(singleCharMatcher.ex());
		anyOf.append("]");
		tokens.add(anyOf.toString());
		return this;
	}

    public RegularExpressionBuilder atLeastOne(SingleCharMatcher singleCharMatcher) {
        squareBrackets(singleCharMatcher, "+");
        return this;
    }

    public RegularExpressionBuilder anyTimes(SingleCharMatcher singleCharMatcher) {
        squareBrackets(singleCharMatcher, "*");
        return this;
    }

    private void squareBrackets(SingleCharMatcher singleCharMatcher, String quantifier) {
        StringBuffer atLeastOne = new StringBuffer("[");
        atLeastOne.append(singleCharMatcher.ex());
        atLeastOne.append("]");
        atLeastOne.append(quantifier);
        tokens.add(atLeastOne.toString());
    }

    public static SingleCharMatcher anyOf() {
		return new SingleCharMatcher();
	}

	public RegularExpressionBuilder anyChar() {
		tokens.add(".");
		return this;
	}

    public RegularExpressionBuilder start() {
        tokens.add("^");
        return this;
    }

    public RegularExpressionBuilder whitespace() {
        tokens.add("\\s");
        return this;
    }
}
